package utils
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import global.BaseWorld;
	
    public class AnimateBitmap extends Bitmap implements IClear
    {
        protected var _intervalTimer:EnterFrameTimer;
        protected var _cellWidth:Number;
        protected var _maxInterval:int;
        protected var _cellArray:Array;
        protected var _hideAfterEnd:Boolean;
        protected var _source:BitmapData;
        protected var _backward:Boolean;
        protected var _timer:EnterFrameTimer;
        protected var _cellHeight:Number;
        protected var _index:int;
        protected var _leftCycles:int = 0;
        protected var _fields:Array;
        protected var _currentField:int = 0;
        protected var _cycles:int = 0;
        protected var _frameRate:int;
        protected var _minInterval:int;

        public function get source():BitmapData
        {
            return _source;
        }
        public function set source(value:BitmapData):void
        {
            _source = value;
            updateCellArray();
        }
        public function get cellWidth():Number
        {
            return _cellWidth;
        }
        public function set cellWidth(value:Number):void
        {
            if (value <= 0) return;
            _cellWidth = value;
            updateCellArray();
        }
        public function get cellHeight():Number
        {
            return _cellHeight;
        }
        public function set cellHeight(value:Number):void
        {
            if (value <= 0) return;
            _cellHeight = value;
            updateCellArray();
        }
        public function get fields():Array
        {
            return _fields;
        }
        public function set fields(value:Array):void
        {
            _fields = value;
            _currentField = 0;
            reset();
        }
        public function get currentField():int
        {
            return _currentField;
        }
        public function set currentField(value:int):void
        {
            if (value >= 0 && value < _fields.length)
            {
                _currentField = value;
            }
        }
        public function get cycles():int
        {
            return _cycles;
        }
        public function set cycles(value:int):void
        {
            _cycles = value < 0 ? 0 : value;
            resetLeftCycles();
        }
        public function get backward():Boolean
        {
            return _backward;
        }
        public function set backward(value:Boolean):void
        {
            _backward = value;
        }
        public function get frameRate():int
        {
            return _frameRate;
        }
        public function set frameRate(value:int):void
        {
            _frameRate = value;
            updateTimer();
        }
        public function get delay():Number
        {
            return 1000 / _frameRate;
        }
        public function set delay(value:Number):void
        {
            _frameRate = int(1000 / value);
            updateTimer();
        }
        public function get hideAfterEnd():Boolean
        {
            return _hideAfterEnd;
        }
        public function set hideAfterEnd(value:Boolean):void
        {
            _hideAfterEnd = value;
        }
        public function get minInterval():int
        {
            return _minInterval;
        }
        public function set minInterval(value:int):void
        {
            _minInterval = value < 0 ? 0 : value;
        }
        public function get maxInterval():int
        {
            return _maxInterval;
        }
        public function set maxInterval(value:int):void
        {
            _maxInterval = value < 0 ? 0 : value;
        }
        public function get leftCycles():int
        {
            return _leftCycles;
        }
        public function get playing():Boolean
        {
            return _timer.running;
        }

        public function AnimateBitmap(source:BitmapData = null,
									  cellWidth:Number = 0,
									  cellHeight:Number = 0,
									  fields:Array = null,
									  cycles:int = 0,
									  backward:Boolean = false,
									  frameRate:int = -1,
									  hideAfterEnd:Boolean = false,
									  minInterval:int = 0,
									  maxInterval:int = 0)
        {
            _source = source;
            _cellWidth = cellWidth;
            _cellHeight = cellHeight;
            _fields = (fields == null) ? [] : fields;
            this.cycles = cycles;
            _backward = backward;
            _frameRate = (frameRate <= 0) ? BaseWorld.getInstance().stage.frameRate : frameRate;
            _hideAfterEnd = hideAfterEnd;
            _minInterval = minInterval < 0 ? 0 : minInterval;
            _maxInterval = maxInterval < 0 ? 0 : maxInterval;
            init();
        }
        protected function init():void
        {
            initCellArray();
            initTimer();
        }
        protected function initCellArray():void
        {
            _cellArray = [];
            updateCellArray();
        }
        protected function initTimer():void
        {
            _timer = new EnterFrameTimer(delay);
            _timer.addEventListener(TimerEvent.TIMER, timerHandler);
            _intervalTimer = new EnterFrameTimer(delay);
            _intervalTimer.repeatCount = 1;
            _intervalTimer.addEventListener(TimerEvent.TIMER_COMPLETE, intervalTimerCompleteHandler);
        }
        protected function timerHandler(event:TimerEvent):void
        {
            var _loc_4:Number = NaN;
            var _loc_5:int = 0;
            var _loc_2:Boolean = false;
            var _loc_3:* = getField(_currentField);
            if (_loc_3.length <= 1)
            {
                return;
            }
            bitmapData = _loc_3[_index];
            if (_backward)
            {
                _index = (_index + _loc_3.length - 1) % _loc_3.length;
                if (_index == (_loc_3.length - 1))
                {
                    _loc_2 = true;
                }
            }
            else
            {
                _index = (_index + 1) % _loc_3.length;
                if (_index == 0)
                {
                    _loc_2 = true;
                }
            }
            if (_loc_2 && _cycles > 0 && _leftCycles > 0)
            {
                var _loc_7:* = _leftCycles - 1;
                _leftCycles = _loc_7;
                if (_leftCycles <= 0)
                {
                    stop();
                    _leftCycles = _cycles;
                    this.dispatchEvent(new Event(Event.COMPLETE));
                }
            }
            if (_loc_2 && _hideAfterEnd)
            {
                bitmapData = null;
            }
            if (_loc_2 && playing && _minInterval + _maxInterval > 0)
            {
                stop();
                if (_maxInterval < _minInterval)
                {
                    _loc_4 = _maxInterval;
                    _maxInterval = _minInterval;
                    _minInterval = _loc_4;
                }
                if (_minInterval == _maxInterval)
                {
                    _intervalTimer.delay = _minInterval;
                }
                else
                {
                    _loc_5 = Math.floor(Math.random() * (_maxInterval - _minInterval)) + _minInterval;
                    _intervalTimer.delay = _loc_5;
                }
                _intervalTimer.start();
            }
        }
        protected function intervalTimerCompleteHandler(event:TimerEvent):void
        {
            play();
        }
        protected function getField(param1:int):Array
        {
            var _loc_2:int = 0;
            var _loc_3:int = 0;
            var _loc_4:int = 0;
            var _loc_5:int = 0;
            if (_cellArray == null || _cellArray.length <= 0 || param1 < 0 || _fields.length > 0 && param1 > (_fields.length - 1))
            {
                return [];
            }
            if (_fields == null || _fields.length <= 0)
            {
                _loc_2 = 0;
                _loc_3 = _cellArray.length;
            }
            else
            {
                _loc_4 = 0;
                _loc_5 = 0;
                while (_loc_5 < param1)
                {
                    
                    _loc_4 = _loc_4 + _fields[_loc_5];
                    _loc_5++;
                }
                _loc_2 = (_loc_4 > _cellArray.length - 1) ? (_cellArray.length - 1) : _loc_4;
                _loc_4 = _loc_4 + _fields[param1];
                _loc_3 = (_loc_4 > _cellArray.length) ? _cellArray.length : _loc_4;
            }
            return _cellArray.slice(_loc_2, _loc_3);
        }
        protected function updateCellArray():void
        {
            var _loc_6:int = 0;
            var _loc_7:BitmapData = null;
            if (_source == null)
            {
                return;
            }
            var _loc_1:* = int(_source.width / _cellWidth);
            var _loc_2:* = int(_source.height / _cellHeight);
            var _loc_3:* = new Rectangle(0, 0, _cellWidth, _cellHeight);
            var _loc_4:* = new Point(0, 0);
            while (_cellArray.length > 0)
            {
                
                BitmapData(_cellArray[0]).dispose();
                _cellArray.shift();
            }
            var _loc_5:int = 0;
            while (_loc_5 < _loc_2)
            {
                
                _loc_6 = 0;
                while (_loc_6 < _loc_1)
                {
                    
                    _loc_7 = new BitmapData(_cellWidth, _cellHeight, true, 0);
                    _loc_3.x = _loc_6 * cellWidth;
                    _loc_3.y = _loc_5 * cellHeight;
                    _loc_7.copyPixels(_source, _loc_3, _loc_4, null, null, true);
                    _cellArray.push(_loc_7);
                    _loc_6++;
                }
                _loc_5++;
            }
            resetLeftCycles();
            reset();
        }
        protected function resetLeftCycles():void
        {
            _leftCycles = _cycles;
        }
        protected function updateTimer():void
        {
            _timer.delay = delay;
        }

        public function play():void
        {
            if (!_timer.running)
            {
                _timer.start();
            }
        }
        public function stop():void
        {
            if (_timer.running)
            {
                _timer.stop();
            }
            reset();
        }
        public function pause():void
        {
            if (_timer.running)
            {
                _timer.stop();
            }
        }
        public function reset():void
        {
            var field:Array = getField(_currentField);
            _index = _backward ? (field.length - 1) : 0;
            bitmapData = _hideAfterEnd ? null : field[_index];
        }
        public function clear():void
        {
            _timer.stop();
            _intervalTimer.stop();
            _cellArray.splice(0, _cellArray.length);
            _fields.splice(0, _fields.length);
            _source = null;
            _backward = false;
            _hideAfterEnd = false;
            _index = 0;
            _cellWidth = 0;
            _cellHeight = 0;
            _frameRate = 0;
            _currentField = 0;
            _cycles = 0;
            _leftCycles = 0;
            _minInterval = 0;
            _maxInterval = 0;
        }
    }
}